package controllers

import (
	"crypto/sha256"
	"encoding/hex"
	"erp/models"
	"erp/services"
	"errors"
	"fmt"
	"math"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"

	"gorm.io/gorm"

	"net/http"
	"strconv"
)

// 库房相关控制器

func GetWarehouses(c *gin.Context, db *gorm.DB) {
	var warehouses []models.Warehouse
	name := c.Query("name_like")
	if name != "" {
		db.Where("name LIKE ?", "%"+name+"%").Order("sort asc, id asc").Find(&warehouses)
	} else {
		db.Order("sort asc, id asc").Find(&warehouses)
	}
	c.JSON(http.StatusOK, warehouses)
}

func CreateWarehouse(c *gin.Context, db *gorm.DB) {
	var warehouse models.Warehouse
	var whAdd models.WarehouseAdd
	if err := c.BindJSON(&whAdd); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	warehouse.Name = whAdd.Name
	warehouse.Sort = whAdd.Sort
	warehouse.GmtCreate = time.Now()
	warehouse.GmtModified = time.Now()
	fmt.Printf("添加库房：%v \n", warehouse)
	db.Create(&warehouse)
	c.JSON(http.StatusCreated, warehouse)
}

func UpdWarehouse(c *gin.Context, db *gorm.DB) {
	var warehouse models.WarehouseUpd
	if err := c.BindJSON(&warehouse); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
	}

	add := &models.Warehouse{
		ID:          warehouse.ID,
		Name:        warehouse.Name,
		GmtModified: time.Now(),
	}

	db.Model(&add).UpdateColumn("name", warehouse.Name)

	c.JSON(http.StatusOK, "true")
}

func UpdateWarehouseOrder(c *gin.Context, db *gorm.DB) {
	var request struct {
		Warehouses []struct {
			ID   uint `json:"id"`
			Sort int  `json:"sort"`
		} `json:"warehouses"`
	}

	if err := c.BindJSON(&request); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// 批量更新数据库中的排序
	for _, w := range request.Warehouses {
		db.Debug().Model(&models.Warehouse{}).Where("id = ?", w.ID).Update("sort", w.Sort)
	}

	c.JSON(http.StatusOK, gin.H{"success": true})
}

func DeleteWarehouse(c *gin.Context, db *gorm.DB) {
	warehouseId := c.Param("warehouseId")
	// 首先删除与该库房相关的所有产品
	if err := db.Where("warehouse_id = ?", warehouseId).Delete(&models.Product{}).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete products"})
		return
	}
	//将物资列表也删除
	db.Delete(&models.Warehouse{}, warehouseId)
	c.JSON(http.StatusOK, gin.H{"message": "Warehouse deleted"})
}

// 物资导出（Excel）
func ExportProductsToExcel(c *gin.Context, db *gorm.DB) {
	// 获取前端传入的物资 ID 列表（多个 ID 以逗号分隔）
	idsParam := c.Query("ids")
	var products []models.Product

	// 如果传入了具体的 ID，则筛选数据
	if idsParam != "" {
		ids := strings.Split(idsParam, ",")
		db.Joins("LEFT JOIN warehouses ON products.warehouse_id = warehouses.id").
			Where("products.id IN (?)", ids).
			Select("products.id, products.name, products.model, products.spec, products.quantity, products.location, products.remark, products.warehouse_id, warehouses.name as warehouse_name").
			Order("products.gmt_create desc").
			Debug().
			Find(&products)
	} else {
		// 如果没有传入 ID，则导出所有物资
		db.Joins("LEFT JOIN warehouses ON products.warehouse_id = warehouses.id").
			Select("products.id, products.name, products.model, products.spec, products.quantity, products.location, products.remark, products.warehouse_id, warehouses.name as warehouse_name").
			Order("products.gmt_create desc").
			Debug().
			Find(&products)
	}

	// 创建 Excel 文件
	f := excelize.NewFile()
	sheetName := "物资列表"
	f.SetSheetName("Sheet1", sheetName)

	// 设置表头
	headers := []string{"序号", "库房名", "物资名称", "型号", "规格", "位置", "数量", "备注"}
	for col, header := range headers {
		colName, _ := excelize.ColumnNumberToName(col + 1) // A, B, C...
		f.SetCellValue(sheetName, colName+"1", header)
	}

	// 填充数据
	for rowIndex, product := range products {
		rowNum := rowIndex + 2 // 从第二行开始填充数据
		f.SetCellValue(sheetName, "A"+strconv.Itoa(rowNum), rowIndex+1)
		f.SetCellValue(sheetName, "B"+strconv.Itoa(rowNum), product.WarehouseName)
		f.SetCellValue(sheetName, "C"+strconv.Itoa(rowNum), product.Name)
		f.SetCellValue(sheetName, "D"+strconv.Itoa(rowNum), product.Model)
		f.SetCellValue(sheetName, "E"+strconv.Itoa(rowNum), product.Spec)
		f.SetCellValue(sheetName, "F"+strconv.Itoa(rowNum), product.Location)
		f.SetCellValue(sheetName, "G"+strconv.Itoa(rowNum), product.Quantity)
		f.SetCellValue(sheetName, "H"+strconv.Itoa(rowNum), product.Remark)
		f.SetCellValue(sheetName, "I"+strconv.Itoa(rowNum), product.InStorage)
		f.SetCellValue(sheetName, "J"+strconv.Itoa(rowNum), product.OutStorage)
		f.SetCellValue(sheetName, "K"+strconv.Itoa(rowNum), product.UserAdmin)
	}

	// 设置 HTTP 头部信息，返回 Excel 文件
	c.Header("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
	c.Header("Content-Disposition", "attachment; filename=products.xlsx")
	c.Header("File-Transfer-Encoding", "binary")

	// 将 Excel 内容写入响应
	_ = f.Write(c.Writer)
}

// 物资导入（Excel）
func ImportProductsFromExcel(c *gin.Context, db *gorm.DB) {
	// 获取上传的文件
	file, err := c.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "上传文件为空"})
		return
	}
	// 打开文件
	f, err := file.Open()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "无法打开上传的文件"})
		return
	}
	defer f.Close()
	// 解析 Excel 文件
	excelFile, err := excelize.OpenReader(f)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "无法解析 Excel 文件"})
		return
	}

	// 获取第一个工作表
	sheetName := excelFile.GetSheetName(0)
	if sheetName == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Excel 文件为空"})
		return
	}

	// 读取行数据
	rows, err := excelFile.GetRows(sheetName)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "无法读取 Excel 数据"})
		return
	}

	// 检查是否有数据
	if len(rows) < 2 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Excel 文件没有数据"})
		return
	}

	// 解析数据并写入数据库
	var products []models.Product
	var updateProducts []models.Product
	var failedProducts []models.Product
	for i, row := range rows {
		if i == 0 {
			continue // 跳过表头
		}

		// 确保数据完整
		if len(row) < 2 || strings.TrimSpace(row[0]) == "" {
			failedProducts = append(failedProducts, models.Product{
				Name:     row[1], // 假设物资名称在第2列
				Quantity: 0,
				Remark:   strconv.Itoa(i) + "，未输入库房名称",
			})
			continue
		}

		// 获取数量字符串并检查是否为负数
		var quantityStr string
		if len(row) > 6 {
			quantityStr = strings.TrimSpace(row[6])
		}

		// 只有当数量不为负数时才检查位置字段
		if quantityStr != "" && !strings.HasPrefix(quantityStr, "-") {
			if len(row) < 5 || strings.TrimSpace(row[4]) == "" {
				failedProducts = append(failedProducts, models.Product{
					Name:     row[1],
					Quantity: 0,
					Remark:   "未输入位置",
				})
				continue
			}
		}
		if len(row) < 2 || strings.TrimSpace(row[1]) == "" {
			failedProducts = append(failedProducts, models.Product{
				Name:     row[1], // 假设物资名称在第2列
				Quantity: 0,
				Remark:   strconv.Itoa(i) + "，物资名称未输入",
			})
			continue
		}
		// 检查其他必填字段
		if len(row) < 6 {
			failedProducts = append(failedProducts, models.Product{
				Name:     row[1], // 假设物资名称在第2列
				Quantity: 0,
				Remark:   strconv.Itoa(i) + "，数据不完整，请重新填写！！！",
			})
			continue
		}

		// 如果之前没有获取数量字符串，则获取
		if quantityStr == "" && len(row) > 6 {
			quantityStr = strings.TrimSpace(row[6])
		}

		reasonStr := func() string {
			if len(row) > 7 && strings.TrimSpace(row[7]) != "" {
				return row[7]
			}
			return ""
		}()

		adminStr := func() string {
			if len(row) > 8 && strings.TrimSpace(row[8]) != "" {
				return row[8]
			}
			return ""
		}()

		// 数量为空则跳过
		if quantityStr == "" || reasonStr == "" || adminStr == "" {
			failedProducts = append(failedProducts, models.Product{
				Name:     row[1],
				Quantity: 0,
				Remark:   strconv.Itoa(i) + "，数据不完整，请重新填写！！！",
			})
			continue
		}

		quantity, err := strconv.Atoi(quantityStr)
		if err != nil {
			failedProducts = append(failedProducts, models.Product{
				Name:     row[1],
				Quantity: 0,
				Remark:   "导入失败：数量必须是有效的数字",
			})
			continue // 跳过无效格式
		}

		// 处理数量为负数的情况（出库）
		recordType := "in"
		quantityForRecord := quantity
		if quantity < 0 {
			recordType = "out"
			quantityForRecord = quantity // 转为正数用于记录
		}

		warehouseName := row[0]
		var warehouse []models.Warehouse
		result := db.Where("name = ?", warehouseName).Debug().Find(&warehouse)
		warehouseID := 0 // 默认库房 ID 为 0

		if result.RowsAffected > 0 {
			warehouseID = int(warehouse[0].ID) // 查询成功，获取库房 ID
		}

		// 获取物资名称
		productName := ""
		if len(row) > 1 && strings.TrimSpace(row[1]) != "" {
			productName = row[1]
		}

		// 检查物资是否已存在
		var existingProduct models.Product
		result = db.Where("name = ? AND warehouse_id = ?", productName, warehouseID).First(&existingProduct)

		// 如果是新增物资且数量为负数，则不允许导入
		if result.RowsAffected == 0 && quantity < 0 {
			failedProducts = append(failedProducts, models.Product{
				Name:     row[1],
				Quantity: i,
				Remark:   "新增物资不能为负数",
			})
			continue
		}

		if result.RowsAffected > 0 {
			// 检查库存是否足够（如果是出库）
			if quantity < 0 && existingProduct.Quantity < -quantity {
				failedProducts = append(failedProducts, models.Product{
					Name:     row[1],
					Quantity: i,
					Remark:   "导入失败：库存不足",
				})
				continue
			}

			// 物资已存在，更新数量和相关信息
			existingProduct.Quantity += quantity
			existingProduct.GmtModified = time.Now()
			// 更新管理员和备注信息
			existingProduct.UserAdmin = adminStr
			existingProduct.Remark = reasonStr
			existingProduct.Types = row[6]
			existingProduct.OutStorage = row[7]
			updateProducts = append(updateProducts, existingProduct)

			// 记录出库/入库记录
			//recordType := "in"
			//if quantity < 0 {
			//	recordType = "out"
			//}
			//createRecord(db, existingProduct.ID, recordType, strconv.Itoa(quantityForRecord), adminStr, reasonStr)
		} else {
			// 物资不存在，创建新物资
			product := models.Product{
				WarehouseID: uint(warehouseID), // 库房 ID
				Name:        productName,       // 物资名称
				Model: func() string {
					if len(row) > 2 && strings.TrimSpace(row[2]) != "" {
						return row[2]
					}
					return ""
				}(), // 物资规格,        // 物资型号
				Spec: func() string {
					if len(row) > 3 && strings.TrimSpace(row[3]) != "" {
						return row[3]
					}
					return ""
				}(), // 物资规格
				Location: func() string {
					if len(row) > 4 && strings.TrimSpace(row[4]) != "" {
						return row[4]
					}
					return ""
				}(), // 位置
				Remark: func() string {
					if len(row) > 5 && strings.TrimSpace(row[5]) != "" {
						return row[5]
					}
					return ""
				}(), // 备注
				InStorage: func() string {
					if len(row) > 6 && strings.TrimSpace(row[6]) != "" {
						return row[6]
					}
					return ""
				}(), // 入库数量
				OutStorage: func() string {
					if len(row) > 7 && strings.TrimSpace(row[7]) != "" {
						return row[7]
					}
					return ""
				}(), // 入库数量
				UserAdmin: func() string {
					if len(row) > 8 && strings.TrimSpace(row[8]) != "" {
						return row[8]
					}
					return ""
				}(), // 入库数量
				Quantity:    quantity,   // 数量
				GmtCreate:   time.Now(), // 创建时间
				GmtModified: time.Now(), // 修改时间
				Types: func() string {
					if len(row) > 6 && strings.TrimSpace(row[6]) != "" {
						return row[6]
					}
					return ""
				}(),
			}
			products = append(products, product)

			// 记录出库/入库记录
			createRecord(db, product.ID, recordType, strconv.Itoa(quantityForRecord), adminStr, reasonStr)
		}
	}

	// 批量插入新物资
	if len(products) > 0 {
		if err := db.Debug().Create(&products).Error; err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "新物资导入失败"})
			return
		}
	}

	// 批量更新已存在物资的数量
	if len(updateProducts) > 0 {
		for _, product := range updateProducts {
			if err := db.Debug().Model(&models.Product{}).Where("id = ?", product.ID).Update("quantity", product.Quantity).Error; err != nil {
				c.JSON(http.StatusInternalServerError, gin.H{"error": "物资数量更新失败" + err.Error()})
				return
			}
		}
	}

	for _, product := range append(products, updateProducts...) {
		if product.OutStorage != "" && product.InStorage != "" {
			inStorageQty, err := strconv.Atoi(strings.TrimSpace(product.Types))
			if err != nil {
				// 如果转换失败，记录错误并跳过
				continue
			}

			// 处理数量为负数的情况（出库）
			recordType := "in"
			quantityForRecord := inStorageQty
			if inStorageQty < 0 {
				recordType = "out"
				quantityForRecord = -inStorageQty // 转为正数用于记录
			}

			createRecord(db, product.ID, recordType, strconv.Itoa(quantityForRecord), product.UserAdmin, product.OutStorage)
		}
	}

	c.JSON(http.StatusOK, gin.H{
		"message": "物资导入成功",
		"count":   products,
		"updated": updateProducts,
		"failed":  failedProducts,
	})
}

// 辅助函数
func createRecord(db *gorm.DB, productID uint, typ, qty, user string, remark string) error {
	quantity, err := strconv.ParseFloat(qty, 64)
	if err != nil {
		return err
	}
	if quantity < 0 {
		return fmt.Errorf("quantity cannot be negative")
	}
	record := models.InventoryRecord{
		ProductID:   productID,
		Type:        typ,
		Quantity:    int(quantity),
		UserName:    user,
		GmtCreate:   time.Now(),
		GmtModified: time.Now(),
		Remark:      remark,
	}
	return db.Create(&record).Error
}

func ExportWarehouses(c *gin.Context, db *gorm.DB) {
	var warehouses []models.Warehouse
	db.Order("sort asc, id asc").Find(&warehouses)
	c.Header("Content-Disposition", "attachment; filename=warehouses.csv")
	c.Header("Content-Type", "text/csv")
	//gocsv.MarshalIntoWriter(warehouses, c.Writer)
}

// 物资相关控制器

func GetProducts(c *gin.Context, db *gorm.DB) {
	page, _ := strconv.Atoi(c.Query("page"))
	pageSize, _ := strconv.Atoi(c.Query("page_size"))
	warehouseId := c.Query("warehouse_id")
	name := c.Query("name_like")
	model := c.Query("model_like")
	specification := c.Query("specification_like")

	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 10
	}

	offset := (page - 1) * pageSize

	var products []models.ProductWithWarehouse
	var totalCount int64

	// 查询物资总数
	query := db.Model(&models.Product{})
	if warehouseId != "" {
		query = query.Where("products.warehouse_id = ?", warehouseId)
	}
	if name != "" {
		query = query.Where("products.name LIKE ?", "%"+name+"%")
	}
	if model != "" {
		query = query.Where("products.model LIKE ?", "%"+model+"%")
	}
	if specification != "" {
		query = query.Where("products.location = ?", specification)
	}

	// 获取总记录数
	query.Count(&totalCount)

	// 查询当前页的物资数据，同时联接库房表，返回物资和库房的字段
	query = query.Joins("LEFT JOIN warehouses ON products.warehouse_id = warehouses.id").
		Select("products.id, products.name, products.model, products.spec, products.quantity, products.location," +
			"products.remark,products.user_admin,products.in_storage,products.out_storage,products.pic,products.email," +
			"products.warehouse_id, warehouses.name as warehouse_name").
		Order("products.gmt_create desc").
		Offset(offset).Limit(pageSize)

	query.Debug().Find(&products)

	// 计算总页数
	totalPages := int(math.Ceil(float64(totalCount) / float64(pageSize)))

	// 返回分页信息和物资数据
	c.JSON(http.StatusOK, gin.H{
		"current_page": page,
		"total_pages":  totalPages,
		"total_count":  totalCount,
		"products":     products,
	})

}

// 上传文件
//func uploadHandler(w http.ResponseWriter, r *http.Request) {
//	r.ParseMultipartForm(10 << 20) // 限制文件大小 10MB
//
//	file, handler, err := r.FormFile("pic")
//	if err != nil {
//		http.Error(w, "无法获取文件", http.StatusBadRequest)
//		return
//	}
//	defer file.Close()
//
//	savePath := "./uploads/" + handler.Filename
//	outFile, err := os.Create(savePath)
//	if err != nil {
//		http.Error(w, "无法保存文件", http.StatusInternalServerError)
//		return
//	}
//	defer outFile.Close()
//
//	_, err = io.Copy(outFile, file)
//	if err != nil {
//		http.Error(w, "文件保存失败", http.StatusInternalServerError)
//		return
//	}
//
//	fileURL := "http://localhost:8080/uploads/" + handler.Filename
//	fmt.Fprintf(w, `{"success": true, "fileUrl": "%s"}`, fileURL)
//}

// 获取单个物资记录
func GetSingleProduct(c *gin.Context, db *gorm.DB) {
	productId := c.Param("productId")

	var product models.ProductWithWarehouse

	result := db.Table("products").
		Joins("LEFT JOIN warehouses ON products.warehouse_id = warehouses.id").
		Select("products.*, warehouses.name as warehouse_name").
		Where("products.id = ?", productId).
		First(&product)

	if result.Error != nil {
		if result.Error == gorm.ErrRecordNotFound {
			c.JSON(http.StatusNotFound, gin.H{"error": "物资不存在"})
			return
		}
		c.JSON(http.StatusInternalServerError, gin.H{"error": "获取物资信息失败"})
		return
	}

	c.JSON(http.StatusOK, product)
}

func CreateProduct(c *gin.Context, db *gorm.DB) {
	var product models.ProductAdd
	if err := c.BindJSON(&product); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
	}

	// 查询库表是否有重复的物资
	var productAddCreate models.Product
	result := db.Table("products").
		Joins("LEFT JOIN warehouses ON products.warehouse_id = warehouses.id").
		Select("products.*, warehouses.name as warehouse_name").
		Where("products.warehouse_id = ? AND products.name = ?", product.WarehouseID, product.Name).
		First(&productAddCreate)

	// 检查查询结果
	if result.Error == nil {
		// 如果没有错误，说明找到了重复的物资
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "数据重复请重新输入"})
		return // 记得在出错时返回
	} else if !errors.Is(result.Error, gorm.ErrRecordNotFound) {
		// 如果是其他错误，返回错误信息
		c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": "查询出错", "error": result.Error.Error()})
		return
	}

	var productAdd = &models.Product{
		Name:        product.Name,
		Model:       product.Model,
		Spec:        product.Spec,
		Location:    product.Location,
		Quantity:    0, // 默认数量为0
		Remark:      product.Remark,
		InStorage:   product.InStorage,
		OutStorage:  product.OutStorage,
		UserAdmin:   product.UserAdmin,
		Pic:         product.Pic,
		Email:       product.Email,
		WarehouseID: product.WarehouseID,
		GmtCreate:   time.Now(),
		GmtModified: time.Now(),
	}

	db.Create(&productAdd)
	c.JSON(http.StatusOK, gin.H{
		"code":    200,
		"message": productAdd})
}

func DeleteProduct(c *gin.Context, db *gorm.DB) {
	productId := c.Param("productId")
	var records []models.InventoryRecord
	db.Where("product_id = ?", productId).Find(&records)
	//if len(records) > 0 {
	//	c.JSON(http.StatusBadRequest, gin.H{"error": "Cannot delete product with existing inventory records"})
	//	return
	//}
	db.Delete(&models.Product{}, productId)
	c.JSON(http.StatusOK, gin.H{"message": "Product deleted"})
}

func DeleteInventory(c *gin.Context, db *gorm.DB) {
	inventoryId := c.Param("inventoryId")
	var records []models.InventoryRecord
	db.Where("id = ?", inventoryId).Find(&records)
	if len(records) < 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Cannot delete product with existing inventory records"})
		return
	}
	db.Delete(&models.InventoryRecord{}, inventoryId)
	c.JSON(http.StatusOK, gin.H{"message": "inventoryId deleted"})
}

func ExportProducts(c *gin.Context, db *gorm.DB) {
	var products []models.Product
	db.Preload("Warehouse").Order("gmt_create desc").Find(&products)
	c.Header("Content-Disposition", "attachment; filename=products.csv")
	c.Header("Content-Type", "text/csv")
	//gocsv.MarshalIntoWriter(products, c.Writer)
}

//出入库记录相关控制器

func GetInventoryRecords(c *gin.Context, db *gorm.DB) {
	page, _ := strconv.Atoi(c.Query("page"))
	pageSize, _ := strconv.Atoi(c.Query("page_size"))
	productId := c.Query("product_id")

	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 10
	}

	offset := (page - 1) * pageSize

	var records []models.InventoryRecord
	var totalCount int64

	// 查询符合条件的总记录数
	query := db.Model(&models.InventoryRecord{})
	if productId != "" {
		query = query.Where("product_id = ?", productId)
	}

	// 获取总记录数
	query.Count(&totalCount)

	// 查询当前页的记录
	query = query.Order("gmt_create desc").Offset(offset).Limit(pageSize)
	query.Find(&records)

	// 计算总页数
	totalPages := int(math.Ceil(float64(totalCount) / float64(pageSize)))

	// 返回分页信息和记录
	c.JSON(http.StatusOK, gin.H{
		"current_page": page,
		"page_size":    pageSize,
		"total_pages":  totalPages,
		"total_count":  totalCount,
		"records":      records,
	})
}

func CreateInventoryRecord(c *gin.Context, db *gorm.DB) {
	var record models.InventoryRecord

	var recordAdd models.InventoryRecordAdd

	c.BindJSON(&recordAdd)

	record.ProductID = recordAdd.ProductID
	record.Quantity = recordAdd.Quantity
	record.Type = recordAdd.Type
	record.Remark = recordAdd.Remark
	record.UserName = recordAdd.UserName
	record.GmtCreate = time.Now()
	record.GmtModified = time.Now()

	// 验证类型
	if record.Type != "in" && record.Type != "out" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "类型输入错误！！！"})
		return
	}

	// 检查物资是否存在
	var product models.Product
	db.First(&product, record.ProductID)
	if product.ID == 0 {
		c.JSON(http.StatusNotFound, gin.H{"error": "没有找到记录"})
		return
	}

	product.UserName += record.UserName
	// 更新物资数量
	if record.Type == "in" {
		product.Quantity += record.Quantity
	} else if record.Type == "out" {
		// 检查库存是否足够
		if product.Quantity < record.Quantity {
			c.JSON(http.StatusBadRequest, gin.H{"error": "库存不足"})
			return
		}
		product.Quantity -= record.Quantity
	}
	db.Debug().Save(&product)

	db.Create(&record)
	c.JSON(http.StatusCreated, record)
}

func ExportInventoryRecords(c *gin.Context, db *gorm.DB) {
	var records []models.InventoryRecord
	db.Preload("Product").Order("gmt_create desc").Find(&records)
	c.Header("Content-Disposition", "attachment; filename=inventory_records.csv")
	c.Header("Content-Type", "text/csv")
	//gocsv.MarshalIntoWriter(records, c.Writer)
}

// 前端页面控制器

func Index(c *gin.Context) {
	c.HTML(http.StatusOK, "index.html", nil)
}

func Inventory(c *gin.Context) {
	productId := c.Param("productId")
	c.HTML(http.StatusOK, "inventory.html", gin.H{"ProductId": productId})
}

func UpdProduct(c *gin.Context, db *gorm.DB) {

	var productUpd models.ProductUpd
	c.BindJSON(&productUpd)

	product := &models.Product{
		ID:          productUpd.ID,
		Name:        productUpd.Name,
		Model:       productUpd.Model,
		Spec:        productUpd.Spec,
		Location:    productUpd.Location,
		Quantity:    productUpd.Quantity,
		Remark:      productUpd.Remark,
		InStorage:   productUpd.InStorage,
		OutStorage:  productUpd.OutStorage,
		UserAdmin:   productUpd.UserAdmin,
		Pic:         productUpd.Pic,
		Email:       productUpd.Email,
		GmtModified: time.Now(),
	}

	db.Model(&product).Where("id = ?", productUpd.ID).Updates(map[string]interface{}{
		"name":         productUpd.Name,
		"model":        productUpd.Model,
		"spec":         productUpd.Spec,
		"location":     productUpd.Location,
		"quantity":     productUpd.Quantity,
		"remark":       productUpd.Remark,
		"in_storage":   productUpd.InStorage,
		"out_storage":  productUpd.OutStorage,
		"user_admin":   productUpd.UserAdmin,
		"pic":          productUpd.Pic,
		"email":        productUpd.Email,
		"gmt_modified": time.Now(),
	})

	c.JSON(http.StatusOK, true)

}

// 密码管理相关控制器

// 生成密码哈希
func hashPassword(password string) string {
	hash := sha256.Sum256([]byte(password))
	return hex.EncodeToString(hash[:])
}

// 检查密码是否存在
func CheckPasswordExists(c *gin.Context, db *gorm.DB) {
	var setting models.SystemSetting
	result := db.Where("setting_key = ?", "delete_password").First(&setting)

	c.JSON(http.StatusOK, gin.H{
		"exists": result.Error == nil,
	})
}

// 设置初始密码
func SetPassword(c *gin.Context, db *gorm.DB) {
	var request struct {
		Password string `json:"password" binding:"required"`
	}

	if err := c.BindJSON(&request); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "密码不能为空"})
		return
	}

	if len(request.Password) < 6 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "密码长度至少6位"})
		return
	}

	// 检查是否已存在密码
	var existingSetting models.SystemSetting
	result := db.Where("setting_key = ?", "delete_password").First(&existingSetting)
	if result.Error == nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "密码已存在，请使用修改密码功能"})
		return
	}

	// 创建新密码设置
	hashedPassword := hashPassword(request.Password)
	setting := models.SystemSetting{
		SettingKey:   "delete_password",
		SettingValue: hashedPassword,
	}

	if err := db.Create(&setting).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "密码设置失败"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "密码设置成功"})
}

// 修改密码
func ChangePassword(c *gin.Context, db *gorm.DB) {
	var request struct {
		CurrentPassword string `json:"currentPassword" binding:"required"`
		NewPassword     string `json:"newPassword" binding:"required"`
	}

	if err := c.BindJSON(&request); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误"})
		return
	}

	if len(request.NewPassword) < 6 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "新密码长度至少6位"})
		return
	}

	// 获取当前密码
	var setting models.SystemSetting
	result := db.Where("setting_key = ?", "delete_password").First(&setting)
	if result.Error != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "密码不存在，请先设置密码"})
		return
	}

	// 验证当前密码
	currentPasswordHash := hashPassword(request.CurrentPassword)
	if setting.SettingValue != currentPasswordHash {
		c.JSON(http.StatusBadRequest, gin.H{"error": "当前密码错误"})
		return
	}

	// 更新密码
	newPasswordHash := hashPassword(request.NewPassword)
	if err := db.Model(&setting).Update("setting_value", newPasswordHash).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "密码修改失败"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "密码修改成功"})
}

// 验证密码
func VerifyPassword(c *gin.Context, db *gorm.DB) {
	var request struct {
		Password string `json:"password" binding:"required"`
	}

	if err := c.BindJSON(&request); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "密码不能为空"})
		return
	}

	// 获取存储的密码
	var setting models.SystemSetting
	result := db.Where("setting_key = ?", "delete_password").First(&setting)
	if result.Error != nil {
		c.JSON(http.StatusOK, gin.H{"valid": false, "error": "密码不存在"})
		return
	}

	// 验证密码
	passwordHash := hashPassword(request.Password)
	isValid := setting.SettingValue == passwordHash

	c.JSON(http.StatusOK, gin.H{"valid": isValid})
}

// 邮件配置管理相关控制器

// GetEmailConfig 获取邮件配置
func GetEmailConfig(c *gin.Context, db *gorm.DB) {
	var settings []models.SystemSetting
	db.Where("setting_key LIKE ?", "email_%").Find(&settings)

	config := make(map[string]string)
	for _, setting := range settings {
		config[setting.SettingKey] = setting.SettingValue
	}

	c.JSON(http.StatusOK, config)
}

// UpdateEmailConfig 更新邮件配置
func UpdateEmailConfig(c *gin.Context, db *gorm.DB) {
	var request struct {
		SMTPHost     string `json:"smtp_host"`
		SMTPPort     string `json:"smtp_port"`
		SMTPUsername string `json:"smtp_username"`
		SMTPPassword string `json:"smtp_password"`
		FromEmail    string `json:"from_email"`
		FromName     string `json:"from_name"`
	}

	if err := c.BindJSON(&request); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误"})
		return
	}

	// 更新邮件配置
	configs := map[string]string{
		"email_smtp_host":     request.SMTPHost,
		"email_smtp_port":     request.SMTPPort,
		"email_smtp_username": request.SMTPUsername,
		"email_smtp_password": request.SMTPPassword,
		"email_from_email":    request.FromEmail,
		"email_from_name":     request.FromName,
	}

	for key, value := range configs {
		var setting models.SystemSetting
		result := db.Where("setting_key = ?", key).First(&setting)

		if result.Error == nil {
			// 更新现有配置
			db.Model(&setting).Update("setting_value", value)
		} else {
			// 创建新配置
			db.Create(&models.SystemSetting{
				SettingKey:   key,
				SettingValue: value,
			})
		}
	}

	c.JSON(http.StatusOK, gin.H{"message": "邮件配置更新成功"})
}

// TestEmail 测试邮件发送
func TestEmail(c *gin.Context, db *gorm.DB) {
	var request struct {
		ToEmail      string `json:"to_email" binding:"required"`
		SMTPHost     string `json:"smtp_host"`
		SMTPPort     string `json:"smtp_port"`
		SMTPUsername string `json:"smtp_username"`
		SMTPPassword string `json:"smtp_password"`
		FromEmail    string `json:"from_email"`
		FromName     string `json:"from_name"`
	}

	if err := c.BindJSON(&request); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误，至少需要提供收件邮箱 to_email"})
		return
	}

	// 如果请求携带了任一配置项，则先写入数据库（相当于快速配置+测试）
	if request.SMTPHost != "" || request.SMTPPort != "" || request.SMTPUsername != "" || request.SMTPPassword != "" || request.FromEmail != "" || request.FromName != "" {
		configs := map[string]string{
			"email_smtp_host":     request.SMTPHost,
			"email_smtp_port":     request.SMTPPort,
			"email_smtp_username": request.SMTPUsername,
			"email_smtp_password": request.SMTPPassword,
			"email_from_email":    request.FromEmail,
			"email_from_name":     request.FromName,
		}
		for key, value := range configs {
			if value == "" {
				continue
			}
			var setting models.SystemSetting
			result := db.Where("setting_key = ?", key).First(&setting)
			if result.Error == nil {
				db.Model(&setting).Update("setting_value", value)
			} else {
				db.Create(&models.SystemSetting{SettingKey: key, SettingValue: value})
			}
		}
	}

	// 读取最新配置
	var settings []models.SystemSetting
	db.Where("setting_key LIKE ?", "email_%").Find(&settings)
	config := make(map[string]string)
	for _, setting := range settings {
		config[setting.SettingKey] = setting.SettingValue
	}

	// 校验必填
	host := config["email_smtp_host"]
	username := config["email_smtp_username"]
	password := config["email_smtp_password"]
	fromEmail := config["email_from_email"]
	fromName := config["email_from_name"]
	if host == "" || username == "" || password == "" || fromEmail == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "请先配置完整的邮件信息（SMTP主机、端口、用户名、授权码、发件邮箱）"})
		return
	}

	// 端口
	port := 465
	if portStr, exists := config["email_smtp_port"]; exists && portStr != "" {
		if p, err := strconv.Atoi(portStr); err == nil {
			port = p
		}
	}

	// 创建服务并发送
	emailConfig := services.EmailConfig{
		SMTPHost:     host,
		SMTPPort:     port,
		SMTPUsername: username,
		SMTPPassword: password,
		FromEmail:    fromEmail,
		FromName:     fromName,
	}
	emailService := services.NewEmailService(emailConfig, db)
	if err := emailService.SendReminderEmail(request.ToEmail, "测试物资", "in_storage", time.Now()); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "邮件发送失败: " + err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "测试邮件发送成功"})
}

// CheckOverdueExists 检查是否存在超过一周的出入库记录
func CheckOverdueExists(c *gin.Context, db *gorm.DB) {
	oneWeekAgo := time.Now().AddDate(0, 0, -7)

	type Result struct{ Count int64 }
	var res Result

	// 仅判断是否存在任意超过一周的记录
	err := db.Table("inventory_records").
		Where("gmt_create < ?", oneWeekAgo).
		Count(&res.Count).Error

	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "查询失败"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"overdue": res.Count > 0, "count": res.Count})
}
